#pragma once
#include <atomic>
#include <condition_variable>
#include <deque>
#include <functional>
#include <memory>
#include <mutex>
#include <optional>
#include <set>
#include <string>
#include <thread>
#include <vector>

namespace lslidar {
enum TimeSyncType { TIME_SYNC_GPS = 0, TIME_SYNC_GPTP = 1 };

enum LidarEchoType { SINGLE_ECHO_MODEL = 0x01, DOUBLE_ECHO_MODEL = 0x02 };

struct LidarPoint {
  int id;
  float hangle;
  float distance;
  int intensity;
  uint64_t timestamp;
  float x;
  float y;
  float z;
};

struct LidarInfo {
  bool first_point_flag{false};
  TimeSyncType time_sync_type;       // lidar当前同步方式
  LidarEchoType echo_type;           // lidar回波模式
  uint64_t package_tm;               // 数据包时间戳
  uint64_t package_tm_last;          // 上一帧数据包时间戳
  uint64_t package_tm_nsec;          // 数据包秒以下时间（nsecond）
  double package_point_interal_nsec; // 数据包内点之间时间间隔
  int package_year;
  int package_month;
  int package_day;
  int package_hour;
  int package_minute;
  int package_second;
};

class LslidarCh128x1 {
public:
  LslidarCh128x1();
  ~LslidarCh128x1();
  void start();
  void stop();
  void lidarDataArrived(uint8_t *pdata, uint16_t len);
  void setLidarFrameCallback(
      std::function<void(const uint64_t &tm,
                         const std::vector<LidarPoint> &point_frame)>
          callback);

private:
  bool _isExit{true};
  std::function<void(const uint64_t &frame_tm,
                     const std::vector<LidarPoint> &point_frame)>
      _pointFrameCallback{nullptr};
  std::shared_ptr<std::thread> _decodeThread{nullptr};
  std::deque<std::vector<uint8_t>> _lidarDataDeque;
  std::vector<LidarPoint> _lidarPointFrame;
  std::mutex _lidarDataMutex;
  std::condition_variable _lidarDataCond;
  LidarInfo _lidarInfo{};
  void decodeLoop();
  void handleSingleEcho(std::vector<uint8_t> &data);   // 单回波处理
  void handleDoubleEcho(std::vector<uint8_t> &data);   // 双回波处理
  void lidarDifopProccess(std::vector<uint8_t> &data); // 设备包解析
  void lidarMsopProccess(std::vector<uint8_t> &data);  // 数据包解析
  void xyzCalculate(LidarPoint&point);
};
} // namespace lslidar
